package com.ltwc.lttv.fragment

import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.ltwc.lttv.Request
import com.ltwc.lttv.activity.MainActivity
import com.ltwc.lttv.adapter.CardAdapter
import com.ltwc.lttv.adapter.LeftAdapter
import com.ltwc.lttv.api.InfoMessage
import com.ltwc.lttv.api.TypeInfoMessage
import com.ltwc.lttv.api.YSP
import com.ltwc.lttv.databinding.ShowBinding
import com.ltwc.lttv.listener.InfoTypeCallBack
import com.ltwc.lttv.listener.ItemListener
import com.ltwc.lttv.models.TV
import com.ltwc.lttv.models.TVListViewModel
import com.ltwc.lttv.models.TVViewModel
import com.ltwc.lttv.models.TypeModel
import com.ltwc.lttv.net.LogUtil
import com.ltwc.lttv.tools.SaveDataTool
import com.ltwc.lttv.tools.Utils.getDateTimestamp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class MainFragment : Fragment(), ItemListener {
    var itemPosition = 0
    private var _binding: ShowBinding? = null
    private val binding get() = _binding!!
    var tvListViewModel = TVListViewModel()
    private var sharedPref: SharedPreferences? = null
    private var lastVideoUrl = ""
    private val handler = Handler(Looper.getMainLooper())
    private lateinit var mUpdateProgramRunnable: UpdateProgramRunnable
    private var ready = 0
    var typeInfoList = mutableListOf<TypeInfoMessage>()
    var listTypeModel = mutableListOf<TypeModel>()
    lateinit var leftAdapter: LeftAdapter
    lateinit var rightAdapter: CardAdapter
    lateinit var left: RecyclerView
    lateinit var right: RecyclerView
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View {
        _binding = ShowBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        activity?.let { YSP.init(it) }
        sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
        buildData()
        view?.post {
            initLeftRecycleView()
            initRightRecycleView()
            observeData()
            itemPosition = sharedPref?.getInt(POSITION, 0)!!
            if (itemPosition >= tvListViewModel.size()) {
                itemPosition = 0
            }
            changeLeft(itemPosition)
            (binding.right.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
                itemPosition,
                0
            )
            tvListViewModel.setItemPosition(itemPosition)
            fragmentReady()
        }
    }

    private fun initLeftRecycleView() {
        left = binding.left
        leftAdapter = LeftAdapter(listTypeModel) { position ->
            (activity as MainActivity).keepRunnable()
            val typeId = listTypeModel[position].type
            val firstRightCurrentIndex =
                tvListViewModel.getTVListViewModel().value?.indexOfFirst { it.getTV().type == typeId }
            if (firstRightCurrentIndex != -1) {
                if (firstRightCurrentIndex != null) {
                    (binding.right.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
                        firstRightCurrentIndex,
                        0
                    )
                }
            }
        }
        leftAdapter.setTypeInfo(typeInfoList)
        getTypeInfo()
        left.layoutManager = LinearLayoutManager(context)
        left.adapter = leftAdapter
        left.descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS
    }

    private fun initRightRecycleView() {
        right = binding.right
        rightAdapter = CardAdapter(viewLifecycleOwner, tvListViewModel)
        rightAdapter.setItemListener(this)
        right.layoutManager =
            LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
        right.adapter = rightAdapter
        mUpdateProgramRunnable = UpdateProgramRunnable()
        right.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                val firstVisibleItemPosition =
                    (recyclerView.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()

                changeLeft(firstVisibleItemPosition)
                (activity as MainActivity).keepRunnable()
            }
        })
        right.descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS
        handler.post(mUpdateProgramRunnable)
    }

    fun changeLeft(firstVisibleItemPosition: Int): Int {
        val typeId =
            tvListViewModel.getTVListViewModel().value?.get(firstVisibleItemPosition)
                ?.getTV()?.type
        val leftPosition = listTypeModel.indexOfFirst { it.type == typeId }
        if (leftPosition != -1) {
            leftAdapter.setHighlightedPosition(leftPosition)
            binding.left.smoothScrollToPosition(leftPosition)
        }
        return leftPosition
    }


    private fun getTypeInfo() {
        this.let {
            Request.initInfoTypeCallBack(object : InfoTypeCallBack {
                override fun call(list: List<TypeInfoMessage>) {
                    typeInfoList.addAll(list)
                    leftAdapter.setTypeInfo(typeInfoList)
                    leftAdapter.notifyDataSetChanged()

                }

                override fun callError(message: String) {
                    LogUtil.e("出错了")
                }
            })
        }
        Request.getTypeList()
    }


    private fun buildData() {
        val mainListString = context?.let { SaveDataTool.getListFromPrefs(it, "main") }
        val gson = Gson()
        val typeToken = object : TypeToken<List<InfoMessage?>?>() {}.type
        val mainList: List<InfoMessage> =
            gson.fromJson<List<InfoMessage>>(mainListString, typeToken)
        var tempType = ""
        var maxIndex = 0
        for (i in mainList.indices) {
            val item: InfoMessage = mainList[i]
            val tv = TV(
                i,
                item.title,
                arrayListOf(item.videoUrl),
                0,
                item.logo,
                if (item.pid != null) item.pid else "",
                if (item.sid != null) item.sid else "",
                if (item.programId != null) item.programId else "",
                item.type,
            );
            val tvViewModel = TVViewModel(tv)
            tvViewModel.needToken = item.needToken == "1";
            if (tempType != item.type) {
                if (tempType != "") {
                    val typeModel = TypeModel(tempType, maxIndex)
                    listTypeModel.add(typeModel)
                }
                tempType = item.type
            } else {
                maxIndex++
                if (i == mainList.size - 1) {
                    val typeModel = TypeModel(tempType, maxIndex)
                    listTypeModel.add(typeModel)
                }
            }
            tvListViewModel.addTVViewModel(tvViewModel)
        }
    }

    private fun observeData() {
        tvListViewModel.getTVListViewModel().value?.forEach { tvViewModel ->
            tvViewModel.errInfo.observe(viewLifecycleOwner) { _ ->
                if (tvViewModel.errInfo.value != null && tvViewModel.id.value == itemPosition) {
                    Toast.makeText(context, tvViewModel.errInfo.value, Toast.LENGTH_SHORT)
                        .show()
                }
            }
            tvViewModel.ready.observe(viewLifecycleOwner) { _ ->

                // not first time && channel not change
                if (tvViewModel.ready.value != null && tvViewModel.id.value == itemPosition && check(
                        tvViewModel
                    )
                ) {
                    LogUtil.i("ready ${tvViewModel.title.value}")
                    (activity as? MainActivity)?.play(tvViewModel)
                }
            }
            tvViewModel.change.observe(viewLifecycleOwner) { _ ->
                if (tvViewModel.change.value != null) {
                    val title = tvViewModel.title.value
                    LogUtil.i("switch $title")
                    if (tvViewModel.pid.value != "") {
                        LogUtil.i("request $title ${tvViewModel.pid.value}")
                        lifecycleScope.launch(Dispatchers.IO) {
                            tvViewModel.let { Request.fetchData(it) }
                        }
                        //TODO:重新请求一次播放链接，貌似央视频链接5分钟左右的时候就会让链接失效,这个时候不想频道列表显示，界面黑一下就好了
                        LogUtil.e("before lastPid $lastPid")
                        if (lastPid == "" || (lastPid != tvViewModel.pid.value)) {
                            (activity as? MainActivity)?.showInfoFragment(tvViewModel)
                        }
                        lastPid = tvViewModel.getTV().pid
                        LogUtil.e("after lastPid $lastPid")
                    } else {
                        if (check(tvViewModel)) {
                            (activity as? MainActivity)?.play(tvViewModel)
                            (activity as? MainActivity)?.showInfoFragment(tvViewModel)
                        }
                    }
                }
            }
        }
    }

    private var lastPid = ""

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
    }

    override fun onItemFocusChange(tvViewModel: TVViewModel, hasFocus: Boolean) {
        if (hasFocus) {
            tvListViewModel.setItemPositionCurrent(tvViewModel.id.value!!)
            (activity as MainActivity).keepRunnable()
        }
    }

    override fun onItemClicked(tvViewModel: TVViewModel) {
        if (this.isHidden) {
            (activity as? MainActivity)?.switchMainFragment()
            return
        }
        if (itemPosition != tvViewModel.id.value!!) {
            itemPosition = tvViewModel.id.value!!
            tvListViewModel.setItemPosition(itemPosition)
            tvListViewModel.getTVViewModel(itemPosition)?.changed()
        }
        (activity as? MainActivity)?.switchMainFragment()
    }

    fun check(tvViewModel: TVViewModel): Boolean {
        val title = tvViewModel.title.value
        val videoUrl = tvViewModel.videoIndex.value?.let { tvViewModel.videoUrl.value?.get(it) }
        if (videoUrl == null || videoUrl == "") {
            LogUtil.e("$title videoUrl is empty")
            return false
        }

        if (videoUrl == lastVideoUrl) {
            LogUtil.e("$title videoUrl is duplication")
            return false
        }

        return true
    }

    fun fragmentReady() {
        ready++
        LogUtil.i("ready $ready")
        if (ready == 4) {
            tvListViewModel.getTVViewModel(itemPosition)?.changed()
        }
    }

    fun play(itemPosition: Int) {
        view?.post {
            if (itemPosition > -1 && itemPosition < tvListViewModel.size()) {
                this.itemPosition = itemPosition
                (binding.right.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
                    itemPosition,
                    0
                )
                changeLeft(itemPosition)
                tvListViewModel.getTVViewModel(itemPosition)?.changed()
            } else {
                Toast.makeText(context, "频道不存在", Toast.LENGTH_SHORT).show()
            }
        }
    }

    fun prev() {
        view?.post {
            itemPosition--
            if (itemPosition == -1) {
                itemPosition = tvListViewModel.size() - 1
            }
            rightAdapter.setHighlightedPosition(itemPosition)
            (binding.right.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
                itemPosition,
                0
            )
            changeLeft(itemPosition)
            tvListViewModel.setItemPosition(itemPosition)
            tvListViewModel.getTVViewModel(itemPosition)?.changed()
        }
    }

    fun next() {
        view?.post {
            itemPosition++
            if (itemPosition == tvListViewModel.size()) {
                itemPosition = 0
            }
            rightAdapter.setHighlightedPosition(itemPosition)
            (binding.right.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
                itemPosition,
                0
            )
            changeLeft(itemPosition)
            tvListViewModel.setItemPosition(itemPosition)
            tvListViewModel.getTVViewModel(itemPosition)?.changed()
        }
    }

    fun updateProgram(tvViewModel: TVViewModel) {
        val timestamp = getDateTimestamp()
        if (timestamp - tvViewModel.programUpdateTime > 60) {
            if (tvViewModel.programId.value != "") {
                if (tvViewModel.program.value!!.isEmpty()) {
                    tvViewModel.programUpdateTime = timestamp
                    Request.fetchProgram(tvViewModel)
                } else {
                    if (timestamp - tvViewModel.program.value!!.last().et < 600) {
                        tvViewModel.programUpdateTime = timestamp
                        Request.fetchProgram(tvViewModel)
                    }
                }
            }
        }
    }

    inner class UpdateProgramRunnable : Runnable {
        override fun run() {
            tvListViewModel.getTVListViewModel().value?.filter { it.programId.value != null }
                ?.forEach { tvViewModel ->
                    updateProgram(
                        tvViewModel
                    )
                }
            handler.postDelayed(this, 60000)
        }
    }

    override fun onStop() {
        LogUtil.i("onStop")
        super.onStop()
        with(sharedPref!!.edit()) {
            putInt(POSITION, itemPosition)
            apply()
        }
        LogUtil.i("POSITION saved")
    }

    override fun onDestroy() {
        LogUtil.i("onDestroy")
        super.onDestroy()
        if (mUpdateProgramRunnable != null) {
            handler.removeCallbacks(mUpdateProgramRunnable)
        }
    }

    override fun onDestroyView() {
        LogUtil.i("onDestroyView")
        super.onDestroyView()
        _binding = null
    }

    override fun onResume() {
        super.onResume()
        view?.post { view?.requestFocus() }
    }

    fun initCurrentStatus() {
        changeLeft(itemPosition)
        (binding.right.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(
            itemPosition,
            0
        )
        left.isFocusable = false
        left.descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS
        right.isFocusable = true
        right.descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS
        right.requestFocus()
    }

    fun leftFocus() {
        right.isFocusable = false
        right.descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS
        left.isFocusable = true
        left.descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS
        left.postDelayed({
            changeLeft(itemPosition)
        }, 50)

    }

    fun rightFocus() {
        left.isFocusable = false
        left.descendantFocusability = ViewGroup.FOCUS_BLOCK_DESCENDANTS
        right.isFocusable = true
        right.descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS
        right.requestFocus()
    }

    companion object {
        private const val TAG = "MainFragment"
        private const val POSITION = "position"
    }
}